home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
fractal
/
frasr182
/
help.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-02
|
38KB
|
1,674 lines
/*
* help.c
*
* This module is linked as an overlay, use ENTER_OVLY and EXIT_OVLY.
*
*
* Revision history:
*
* 2-26-90 EAN Initial version.
*
*
*/
#ifndef TEST /* kills all those assert macros in production version */
#define NDEBUG
#endif
#define INCLUDE_COMMON /* include common code in helpcom.h */
#include <stdio.h>
#include <stdlib.h>
#ifndef XFRACT
#include <io.h>
#include <dos.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef XFRACT
#include <unistd.h>
#endif
#include "fractint.h"
#include "helpcom.h"
#include "helpdefs.h"
#include "prototyp.h"
#define MAX_HIST 16 /* number of pages we'll remember */
#define ALT_F1 1104
#define BACK_TAB 1015
#define BACKSPACE 8
#define ACTION_CALL 0 /* values returned by help_topic() */
#define ACTION_PREV 1
#define ACTION_PREV2 2 /* special - go back two topics */
#define ACTION_INDEX 3
#define ACTION_QUIT 4
#define F_HIST (1<<0) /* flags for help_topic() */
#define F_INDEX (1<<1)
#define MAX_PAGE_SIZE (80*25) /* no page of text may be larger */
#define TEXT_START_ROW 2 /* start print the help text here */
typedef struct
{
BYTE r, c;
int width;
unsigned offset;
int topic_num;
unsigned topic_off;
} LINK;
typedef struct
{
int topic_num;
unsigned topic_off;
} LABEL;
typedef struct
{
unsigned offset;
unsigned len;
int margin;
} PAGE;
typedef struct
{
int topic_num;
unsigned topic_off;
int link;
} HIST;
struct help_sig_info
{
unsigned long sig;
int version;
unsigned long base; /* only if added to fractint.exe */
} ;
void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg );
static int print_doc_msg_func(int pnum, int num_pages);
void help_overlay(void) { }
/* stuff from fractint */
extern int lookatmouse;
extern long timer_start;
extern int helpmode;
extern int text_type; /* 0=real color text, 1=640x200x2, 2=??mono?? */
extern int textcbase;
extern int textrbase;
extern SEGTYPE extraseg;
extern int release;
int putstringcenter (int row, int col, int width, int attr, char far *msg);
void helptitle (void);
void stackscreen (void);
void unstackscreen (void);
void findpath (char *filename, char *path);
static int help_file = -1; /* help file handle */
static long base_off; /* offset to help info in help file */
static int max_links; /* max # of links in any page */
static int max_pages; /* max # of pages in any topic */
static int num_label; /* number of labels */
static int num_topic; /* number of topics */
static int curr_hist = 0; /* current pos in history */
/* these items alloc'ed in init_help... */
static long far *topic_offset; /* 4*num_topic */
static LABEL far *label; /* 4*num_label */
static HIST far *hist; /* 6*MAX_HIST (96 bytes) */
/* these items alloc'ed only while help is active... */
static char far *buffer; /* MAX_PAGE_SIZE (2048 bytes) */
static LINK far *link_table; /* 10*max_links */
static PAGE far *page_table; /* 4*max_pages */
static void help_seek(long pos)
{
lseek(help_file, base_off+pos, SEEK_SET);
}
static void displayc(int row, int col, int color, int ch)
{
#ifndef XFRACT
static char *s = "?";
#else
static char s[] = "?";
#endif
if (text_type == 1) /* if 640x200x2 mode */
{
/*
* This is REALLY ugly, but it works. Non-current links (ones that
* would be bold if 640x200 supported it) are in upper-case and the
* current item is inversed.
*
*/
if (color & INVERSE)
color = (signed int)INVERSE;
else if (color & BRIGHT)
{
color = 0; /* normal */
if (ch>='a' && ch<='z')
ch += 'A' - 'a';
}
else
color = 0; /* normal */
}
s[0] = ch;
putstring(row, col, color, s);
}
static void display_text(int row, int col, int color, char far *text, unsigned len)
{
while (len-- > 0)
{
if (*text == CMD_LITERAL)
{
++text;
--len;
}
displayc(row, col++, color, *text++);
}
}
static void display_parse_text(char far *text, unsigned len, int start_margin, int *num_link, LINK far *link)
{
char far *curr;
int row, col;
int tok;
int size,
width;
textcbase = SCREEN_INDENT;
textrbase = TEXT_START_ROW;
curr = text;
row = 0;
col = 0;
size = width = 0;
if (start_margin >= 0)
tok = TOK_PARA;
else
tok = -1;
while ( 1 )
{
switch ( tok )
{
case TOK_PARA:
{
int indent,
margin;
if (size > 0)
{
++curr;
indent = *curr++;
margin = *curr++;
len -= 3;
}
else
{
indent = start_margin;
margin = start_margin;
}
col = indent;
while (1)
{
tok = find_token_length(ONLINE, curr, len, &size, &width);
if (tok == TOK_DONE || tok == TOK_NL || tok == TOK_FF )
break;
if (tok == TOK_PARA)
{
col = 0; /* fake a new-line */
row++;
break;
}
if (tok == TOK_XONLINE || tok == TOK_XDOC)
{
curr += size;
len -= size;
continue;
}
/* now tok is TOK_SPACE or TOK_LINK or TOK_WORD */
if (col+width > SCREEN_WIDTH)
{ /* go to next line... */
col = margin;
++row;
if ( tok == TOK_SPACE )
width = 0; /* skip spaces at start of a line */
}
if (tok == TOK_LINK)
{
display_text(row, col, C_HELP_LINK, curr+1+3*sizeof(int), width);
if (num_link != NULL)
{
link[*num_link].r = row;
link[*num_link].c = col;
link[*num_link].topic_num = getint(curr+1);
link[*num_link].topic_off = getint(curr+1+sizeof(int));
link[*num_link].offset = (unsigned) ((curr+1+3*sizeof(int)) - text);
link[*num_link].width = width;
++(*num_link);
}
}
else if (tok == TOK_WORD )
display_text(row, col, C_HELP_BODY, curr, width);
col += width;
curr += size;
len -= size;
}
width = size = 0;
break;
}
case TOK_CENTER:
col = find_line_width(ONLINE, curr, len);
col = (SCREEN_WIDTH-col)/2;
if (col < 0)
col = 0;
break;
case TOK_NL:
col = 0;
++row;
break;
case TOK_LINK:
display_text(row, col, C_HELP_LINK, curr+1+3*sizeof(int), width);
if (num_link != NULL)
{
link[*num_link].r = row;
link[*num_link].c = col;
link[*num_link].topic_num = getint(curr+1);
link[*num_link].topic_off = getint(curr+1+sizeof(int));
link[*num_link].offset = (unsigned) ((curr+1+3*sizeof(int)) - text);
link[*num_link].width = width;
++(*num_link);
}
break;
case TOK_XONLINE: /* skip */
case TOK_FF: /* ignore */
case TOK_XDOC: /* ignore */
case TOK_DONE:
case TOK_SPACE:
break;
case TOK_WORD:
display_text(row, col, C_HELP_BODY, curr, width);
break;
} /* switch */
curr += size;
len -= size;
col += width;
if (len == 0)
break;
tok = find_token_length(ONLINE, curr, len, &size, &width);
} /* while */
textcbase = 0;
textrbase = 0;
}
static void color_link(LINK far *link, int color)
{
textcbase = SCREEN_INDENT;
textrbase = TEXT_START_ROW;
if (text_type == 1) /* if 640x200x2 mode */
display_text(link->r, link->c, color, buffer+link->offset, link->width);
else
setattr(link->r, link->c, color, link->width);
textcbase = 0;
textrbase = 0;
}
/* #define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR_KEYS,name), putstring(-1,-1,C_HELP_INSTR," "descrip" ") */
#ifndef XFRACT
#define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR,name); putstring(-1,-1,C_HELP_INSTR,":"descrip" ")
#else
#define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR,name);\
putstring(-1,-1,C_HELP_INSTR,":");\
putstring(-1,-1,C_HELP_INSTR,descrip);\
putstring(-1,-1,C_HELP_INSTR," ")
#endif
static void helpinstr(void)
{
int ctr;
for (ctr=0; ctr<80; ctr++)
putstring(24, ctr, C_HELP_INSTR, " ");
movecursor(24, 1);
PUT_KEY("F1", "Index");
#ifndef XFRACT
PUT_KEY("\030\031\033\032", "Select");
#else
PUT_KEY("K J H L", "Select");
#endif
PUT_KEY("Enter", "Go to");
PUT_KEY("Backspace", "Last topic");
PUT_KEY("Escape", "Exit help");
}
static void printinstr(void)
{
int ctr;
for (ctr=0; ctr<80; ctr++)
putstring(24, ctr, C_HELP_INSTR, " ");
movecursor(24, 1);
PUT_KEY("Escape", "Abort");
}
#undef PUT_KEY
static void display_page(char far *title, char far *text, unsigned text_len, int page, int num_pages, int start_margin, int *num_link, LINK far *link)
{
char temp[9];
helptitle();
helpinstr();
setattr(2, 0, C_HELP_BODY, 80*22);
putstringcenter(1, 0, 80, C_HELP_HDG, title);
sprintf(temp, "%2d of %d", page+1, num_pages);
#ifndef XFRACT
putstring(1, 79-(6 + ((num_pages>=10)?2:1)), C_HELP_INSTR, temp);
#else
/* Some systems (Ultrix) mess up if you write to column 80 */
putstring(1, 78-(6 + ((num_pages>=10)?2:1)), C_HELP_INSTR, temp);
#endif
if (text != NULL)
display_parse_text(text, text_len, start_margin, num_link, link);
movecursor(25, 80); /* hide cursor */
}
/*
* int overlap(int a, int a2, int b, int b2);
*
* If a, a2, b, and b2 are points on a line, this function returns the
* distance of intersection between a-->a2 and b-->b2. If there is no
* intersection between the lines this function will return a negative number
* representing the distance between the two lines.
*
* There are six possible cases of intersection between the lines:
*
* a a2
* | |
* b b2 | | b b2
* |---(1)---| | | |---(2)---|
* | |
* b | b2 b | b2
* |------(3)----| |------(4)-----|
* | |
* b | | b2
* |------+--------(5)----------+---|
* | |
* | b b2 |
* | |--(6)--| |
* | |
* | |
*
*/
static int overlap(int a, int a2, int b, int b2)
{
if ( b < a )
{
if ( b2 >= a2 )
return ( a2 - a ); /* case (5) */
return ( b2 - a ); /* case (1), case (3) */
}
if ( b2 <= a2 )
return ( b2 - b ); /* case (6) */
return ( a2 - b ); /* case (2), case (4) */
}
static int dist(int a, int b)
{
int t = a - b;
return (abs(t));
}
#ifdef __TURBOC__
# pragma warn -def /* turn off "Possible use before definition" warning */
#endif
static int find_link_updown(LINK far *link, int num_link, int curr_link, int up)
{
int ctr,
curr_c2,
best_overlap,
temp_overlap;
LINK far *curr,
far *temp,
far *best;
int temp_dist;
curr = &link[curr_link];
best = NULL;
curr_c2 = curr->c + curr->width - 1;
for (ctr=0, temp=link; ctr<num_link; ctr++, temp++)
{
if ( ctr != curr_link &&
( (up && temp->r < curr->r) || (!up && temp->r > curr->r) ) )
{
temp_overlap = overlap(curr->c, curr_c2, temp->c, temp->c+temp->width-1);
/* if >= 3 lines between, prioritize on vertical distance: */
if ((temp_dist = dist(temp->r, curr->r)) >= 4)
temp_overlap -= temp_dist * 100;
if (best != NULL)
{
if ( best_overlap >= 0 && temp_overlap >= 0 )
{ /* if they're both under curr set to closest in y dir */
if ( dist(best->r, curr->r) > temp_dist )
best = NULL;
}
else
{
if ( best_overlap < temp_overlap )
best = NULL;
}
}
if (best == NULL)
{
best = temp;
best_overlap = temp_overlap;
}
}
}
return ( (best==NULL) ? -1 : (int)(best-link) );
}
static int find_link_leftright(LINK far *link, int num_link, int curr_link, int left)
{
int ctr,
curr_c2,
best_c2,
temp_c2,
best_dist,
temp_dist;
LINK far *curr,
far *temp,
far *best;
curr = &link[curr_link];
best = NULL;
curr_c2 = curr->c + curr->width - 1;
for (ctr=0, temp=link; ctr<num_link; ctr++, temp++)
{
temp_c2 = temp->c + temp->width - 1;
if ( ctr != curr_link &&
( (left && temp_c2 < curr->c) || (!left && temp->c > curr_c2) ) )
{
temp_dist = dist(curr->r, temp->r);
if (best != NULL)
{
if ( best_dist == 0 && temp_dist == 0 ) /* if both on curr's line... */
{
if ( ( left && dist(curr->c, best_c2) > dist(curr->c, temp_c2) ) ||
( !left && dist(curr_c2, best->c) > dist(curr_c2, temp->c) ) )
best = NULL;
}
else
{
if ( best_dist >= temp_dist ) /* if temp is closer... */
best = NULL;
}
} /* if (best...) */
if (best == NULL)
{
best = temp;
best_dist = temp_dist;
best_c2 = temp_c2;
}
}
} /* for */
return ( (best==NULL) ? -1 : (int)(best-link) );
}
#ifdef __TURBOC__
# pragma warn .def /* back to default */
# pragma warn -par /* now turn off "Parameter not used" warning */
#endif
static int find_link_key(LINK far *link, int num_link, int curr_link, int key)
{
switch (key)
{
case TAB: return ( (curr_link>=num_link-1) ? -1 : curr_link+1 );
case BACK_TAB: return ( (curr_link<=0) ? -1 : curr_link-1 );
default: assert(0); return (-1);
}
}
#ifdef __TURBOC__
# pragma warn .par /* back to default */
#endif
static int do_move_link(LINK far *link, int num_link, int *curr, int (*f)(LINK far *,int,int,int), int val)
{
int t;
if (num_link > 1)
{
if ( f == NULL )
t = val;
else
t = (*f)(link, num_link, *curr, val);
if ( t >= 0 && t != *curr )
{
color_link(&link[*curr], C_HELP_LINK);
*curr = t;
color_link(&link[*curr], C_HELP_CURLINK);
return (1);
}
}
return (0);
}
static int help_topic(HIST *curr, HIST *next, int flags)
{
int len;
int key;
int num_pages;
int num_link;
int page;
int curr_link;
char title[81];
long where;
int draw_page;
int action;
BYTE ch;
where = topic_offset[curr->topic_num]+sizeof(int); /* to skip flags */
curr_link = curr->link;
help_seek(where);
read(help_file, (char *)&num_pages, sizeof(int));
assert(num_pages>0 && num_pages<=max_pages);
farread(help_file, (char far *)page_table, 3*sizeof(int)*num_pages);
read(help_file, &ch, 1);
len = ch;
assert(len<81);
read(help_file, (char *)title, len);
title[len] = '\0';
where += sizeof(int) + num_pages*3*sizeof(int) + 1 + len + sizeof(int);
for(page=0; page<num_pages; page++)
if (curr->topic_off >= page_table[page].offset &&
curr->topic_off < page_table[page].offset+page_table[page].len )
break;
assert(page < num_pages);
action = -1;
draw_page = 2;
do
{
if (draw_page)
{
help_seek(where+page_table[page].offset);
farread(help_file, buffer, page_table[page].len);
num_link = 0;
display_page(title, buffer, page_table[page].len, page, num_pages,
page_table[page].margin, &num_link, link_table);
if (draw_page==2)
{
assert(num_link<=0 || (curr_link>=0 && curr_link<num_link));
}
else if (draw_page==3)
curr_link = num_link - 1;
else
curr_link = 0;
if (num_link > 0)
color_link(&link_table[curr_link], C_HELP_CURLINK);
draw_page = 0;
}
key = getakey();
switch(key)
{
case PAGE_DOWN:
if (page<num_pages-1)
{
page++;
draw_page = 1;
}
break;
case PAGE_UP:
if (page>0)
{
page--;
draw_page = 1;
}
break;
case HOME:
if ( page != 0 )
{
page = 0;
draw_page = 1;
}
else
do_move_link(link_table, num_link, &curr_link, NULL, 0);
break;
case END:
if ( page != num_pages-1 )
{
page = num_pages-1;
draw_page = 3;
}
else
do_move_link(link_table, num_link, &curr_link, NULL, num_link-1);
break;
case TAB:
if ( !do_move_link(link_table, num_link, &curr_link, find_link_key, key) &&
page<num_pages-1 )
{
++page;
draw_page = 1;
}
break;
case BACK_TAB:
if ( !do_move_link(link_table, num_link, &curr_link, find_link_key, key) &&
page>0 )
{
--page;
draw_page = 3;
}
break;
case DOWN_ARROW:
if ( !do_move_link(link_table, num_link, &curr_link, find_link_updown, 0) &&
page<num_pages-1 )
{
++page;
draw_page = 1;
}
break;
case UP_ARROW:
if ( !do_move_link(link_table, num_link, &curr_link, find_link_updown, 1) &&
page>0 )
{
--page;
draw_page = 3;
}
break;
case LEFT_ARROW:
do_move_link(link_table, num_link, &curr_link, find_link_leftright, 1);
break;
case RIGHT_ARROW:
do_move_link(link_table, num_link, &curr_link, find_link_leftright, 0);
break;
case ESC: /* exit help */
action = ACTION_QUIT;
break;
case BACKSPACE: /* prev topic */
case ALT_F1:
if (flags & F_HIST)
action = ACTION_PREV;
break;
case F1: /* help index */
if (!(flags & F_INDEX))
action = ACTION_INDEX;
break;
case ENTER:
case ENTER_2:
if (num_link > 0)
{
next->topic_num = link_table[curr_link].topic_num;
next->topic_off = link_table[curr_link].topic_off;
action = ACTION_CALL;
}
break;
} /* switch */
}
while ( action == -1 );
curr->topic_off = page_table[page].offset;
curr->link = curr_link;
return (action);
}
int help(int action)
{
static char far unknowntopic_msg[] = "Unknown Help Topic";
HIST curr;
int oldlookatmouse;
int oldhelpmode;
int flags;
HIST next;
ENTER_OVLY(OVLY_HELP);
if (helpmode == -1) /* is help disabled? */
{
EXIT_OVLY;
return (0);
}
if (help_file == -1)
{
buzzer(2);
EXIT_OVLY;
return (0);
}
buffer = farmemalloc((long)MAX_PAGE_SIZE + sizeof(LINK)*max_links +
sizeof(PAGE)*max_pages);
if (buffer == NULL)
{
buzzer(2);
EXIT_OVLY;
return (0);
}
link_table = (LINK far *)(&buffer[MAX_PAGE_SIZE]);
page_table = (PAGE far *)(&link_table[max_links]);
oldlookatmouse = lookatmouse;
lookatmouse = 0;
timer_start -= clock_ticks();
stackscreen();
if (helpmode >= 0)
{
next.topic_num = label[helpmode].topic_num;
next.topic_off = label[helpmode].topic_off;
}
else
{
next.topic_num = helpmode;
next.topic_off = 0;
}
oldhelpmode = helpmode;
if (curr_hist <= 0)
action = ACTION_CALL; /* make sure it isn't ACTION_PREV! */
do
{
switch(action)
{
case ACTION_PREV2:
if (curr_hist > 0)
curr = hist[--curr_hist];
/* fall-through */
case ACTION_PREV:
if (curr_hist > 0)
curr = hist[--curr_hist];
break;
case ACTION_QUIT:
break;
case ACTION_INDEX:
next.topic_num = label[HELP_INDEX].topic_num;
next.topic_off = label[HELP_INDEX].topic_off;
/* fall-through */
case ACTION_CALL:
curr = next;
curr.link = 0;
break;
} /* switch */
flags = 0;
if (curr.topic_num == label[HELP_INDEX].topic_num)
flags |= F_INDEX;
if (curr_hist > 0)
flags |= F_HIST;
if ( curr.topic_num >= 0 )
action = help_topic(&curr, &next, flags);
else
{
if ( curr.topic_num == -100 )
{
print_document("FRACTINT.DOC", print_doc_msg_func, 1);
action = ACTION_PREV2;
}
else if ( curr.topic_num == -101 )
action = ACTION_PREV2;
else
{
display_page(unknowntopic_msg, NULL, 0, 0, 1, 0, NULL, NULL);
action = -1;
while (action == -1)
{
switch (getakey())
{
case ESC: action = ACTION_QUIT; break;
case ALT_F1: action = ACTION_PREV; break;
case F1: action = ACTION_INDEX; break;
} /* switch */
} /* while */
}
} /* else */
if ( action != ACTION_PREV && action != ACTION_PREV2 )
{
if (curr_hist >= MAX_HIST)
{
int ctr;
for (ctr=0; ctr<MAX_HIST-1; ctr++)
hist[ctr] = hist[ctr+1];
curr_hist = MAX_HIST-1;
}
hist[curr_hist++] = curr;
}
}
while (action != ACTION_QUIT);
farmemfree((BYTE far *)buffer);
unstackscreen();
lookatmouse = oldlookatmouse;
helpmode = oldhelpmode;
timer_start += clock_ticks();
EXIT_OVLY;
return(0);
}
static int dos_version(void)
{
#ifndef XFRACT
union REGS r;
r.x.ax = 0x3000;
intdos(&r, &r);
return (r.h.al*100 + r.h.ah);
#else
return 0;
#endif
}
static int exe_path(char *filename, char *path)
{
#ifndef XFRACT
char *ptr;
if (dos_version() >= 300) /* DOS version 3.00+ ? */
{
#ifdef __TURBOC__
strcpy(path, _argv[0]);
#else /* assume MSC */
extern char **__argv;
strcpy(path, __argv[0]); /* note: __argv may be undocumented in MSC */
#endif
ptr = strrchr(path, SLASHC);
if (ptr == NULL)
ptr = path;
else
++ptr;
strcpy(ptr, filename);
return (1);
}
return (0);
#else
strcpy(path,SRCDIR);
strcat(path,"/");
strcat(path,filename);
return 1;
#endif
}
static int find_file(char *filename, char *path)
{
int handle;
if ( exe_path(filename, path) )
if ( (handle=open(path, O_RDONLY)) != -1)
{
close(handle);
return (1);
}
findpath(filename,path);
return ( (path[0]) ? 1 : 0);
}
static int _read_help_topic(int topic, int off, int len, VOIDFARPTR buf)
{
static int curr_topic = -1;
static long curr_base;
static int curr_len;
int read_len;
if ( topic != curr_topic )
{
int t;
char ch;
curr_topic = topic;
curr_base = topic_offset[topic];
curr_base += sizeof(int); /* skip flags */
help_seek(curr_base);
read(help_file, (char *)&t, sizeof(int)); /* read num_pages */
curr_base += sizeof(int) + t*3*sizeof(int); /* skip page info */
if (t>0)
help_seek(curr_base);
read(help_file, &ch, 1); /* read title_len */
t = ch;
curr_base += 1 + t; /* skip title */
if (t>0)
help_seek(curr_base);
read(help_file, (char *)&curr_len, sizeof(int)); /* read topic len */
curr_base += sizeof(int);
}
read_len = (off+len > curr_len) ? curr_len - off : len;
if (read_len > 0)
{
help_seek(curr_base + off);
farread(help_file, (char far *)buf, read_len);
}
return ( curr_len - (off+len) );
}
int read_help_topic(int label_num, int off, int len, VOIDFARPTR buf)
/*
* reads text from a help topic. Returns number of bytes from (off+len)
* to end of topic. On "EOF" returns a negative number representing
* number of bytes not read.
*/
{
int ret;
ENTER_OVLY(OVLY_HELP);
ret = _read_help_topic(label[label_num].topic_num,
label[label_num].topic_off + off, len, buf);
EXIT_OVLY;
return ( ret );
}
#define PRINT_BUFFER_SIZE (32767) /* max. size of help topic in doc. */
#define TEMP_FILE_NAME "HELP.$$$" /* temp file for storing extraseg */
/* while printing document */
#define MAX_NUM_TOPIC_SEC (10) /* max. number of topics under any */
/* single section (CONTENT) */
typedef struct PRINT_DOC_INFO
{
int cnum; /* current CONTENT num */
int tnum; /* current topic num */
long content_pos; /* current CONTENT item offset in file */
int num_page; /* total number of pages in document */
int num_contents, /* total number of CONTENT entries */
num_topic; /* number of topics in current CONTENT */
int topic_num[MAX_NUM_TOPIC_SEC]; /* topic_num[] for current CONTENT entry */
char far *buffer; /* text buffer */
char id[81]; /* buffer to store id in */
char title[81]; /* buffer to store title in */
#ifndef XFRACT
int (*msg_func)(int pnum, int num_page);
#else
int (*msg_func)();
int pnum;
#endif
FILE *file; /* file to sent output to */
int margin; /* indent text by this much */
int start_of_line; /* are we at the beginning of a line? */
int spaces; /* number of spaces in a row */
} PRINT_DOC_INFO;
void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg );
static void printerc(PRINT_DOC_INFO *info, int c, int n)
{
while ( n-- > 0 )
{
if (c==' ')
++info->spaces;
else if (c=='\n' || c=='\f')
{
info->start_of_line = 1;
info->spaces = 0; /* strip spaces before a new-line */
putc(c, info->file);
}
else
{
if (info->start_of_line)
{
info->spaces += info->margin;
info->start_of_line = 0;
}
while (info->spaces > 0)
{
fputc(' ', info->file);
--info->spaces;
}
fputc(c, info->file);
}
}
}
static void printers(PRINT_DOC_INFO *info, char far *s, int n)
{
if (n > 0)
{
while ( n-- > 0 )
printerc(info, *s++, 1);
}
else
{
while ( *s != '\0' )
printerc(info, *s++, 1);
}
}
static int print_doc_get_info(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
{
int t;
BYTE ch;
switch (cmd)
{
case PD_GET_CONTENT:
if ( ++info->cnum >= info->num_contents )
return (0);
help_seek( info->content_pos );
read(help_file, (char *)&t, sizeof(int)); /* read flags */
info->content_pos += sizeof(int);
pd->new_page = (t & 1) ? 1 : 0;
read(help_file, &ch, 1); /* read id len */
t = ch;
assert(t<80);
read(help_file, (char *)info->id, t); /* read the id */
info->content_pos += 1 + t;
info->id[t] = '\0';
read(help_file, (char *)&ch, 1); /* read title len */
t = ch;
assert(t<80);
read(help_file, (char *)info->title, t); /* read the title */
info->content_pos += 1 + t;
info->title[t] = '\0';
read(help_file, (char *)&ch, 1); /* read num_topic */
t = ch;
assert(t<MAX_NUM_TOPIC_SEC);
read(help_file, (char *)info->topic_num, t*sizeof(int)); /* read topic_num[] */
info->num_topic = t;
info->content_pos += 1 + t*sizeof(int);
info->tnum = -1;
pd->id = info->id;
pd->title = info->title;
return (1);
case PD_GET_TOPIC:
if ( ++info->tnum >= info->num_topic )
return (0);
t = _read_help_topic(info->topic_num[info->tnum], 0, PRINT_BUFFER_SIZE, info->buffer);
assert(t <= 0);
pd->curr = info->buffer;
pd->len = PRINT_BUFFER_SIZE + t; /* same as ...SIZE - abs(t) */
return (1);
case PD_GET_LINK_PAGE:
pd->i = getint(pd->s+sizeof(long));
return ( (pd->i == -1) ? 0 : 1 );
case PD_RELEASE_TOPIC:
return (1);
default:
return (0);
}
}
static int print_doc_output(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
{
switch (cmd)
{
case PD_HEADING:
{
char line[81];
char buff[40];
int width = PAGE_WIDTH + PAGE_INDENT;
int keep_going;
if ( info->msg_func != NULL )
keep_going = (*info->msg_func)(pd->pnum, info->num_page);
else
keep_going = 1;
info->margin = 0;
memset(line, ' ', 81);
sprintf(buff, "Fractint Version %d.%01d%c",release/100, (release%100)/10,
( (release%10) ? '0'+(release%10) : ' ') );
memmove(line + ( (width-strlen(buff)) / 2)-4, buff, strlen(buff));
sprintf(buff, "Page %d", pd->pnum);
memmove(line + (width - strlen(buff)), buff, strlen(buff));
printerc(info, '\n', 1);
printers(info, line, width);
printerc(info, '\n', 2);
info->margin = PAGE_INDENT;
return ( keep_going );
}
case PD_FOOTING:
info->margin = 0;
printerc(info, '\f', 1);
info->margin = PAGE_INDENT;
return (1);
case PD_PRINT:
printers(info, pd->s, pd->i);
return (1);
case PD_PRINTN:
printerc(info, *pd->s, pd->i);
return (1);
case PD_PRINT_SEC:
info->margin = TITLE_INDENT;
if (pd->id[0] != '\0')
{
printers(info, pd->id, 0);
printerc(info, ' ', 1);
}
printers(info, pd->title, 0);
printerc(info, '\n', 1);
info->margin = PAGE_INDENT;
return (1);
case PD_START_SECTION:
case PD_START_TOPIC:
case PD_SET_SECTION_PAGE:
case PD_SET_TOPIC_PAGE:
case PD_PERIODIC:
return (1);
default:
return (0);
}
}
static int print_doc_msg_func(int pnum, int num_pages)
{
char temp[10];
int key;
if ( pnum == -1 ) /* successful completion */
{
buzzer(0);
putstringcenter(7, 0, 80, C_HELP_LINK, "Done -- Press any key");
getakey();
return (0);
}
if ( pnum == -2 ) /* aborted */
{
buzzer(1);
putstringcenter(7, 0, 80, C_HELP_LINK, "Aborted -- Press any key");
getakey();
return (0);
}
if (pnum == 0) /* initialization */
{
helptitle();
printinstr();
setattr(2, 0, C_HELP_BODY, 80*22);
putstringcenter(1, 0, 80, C_HELP_HDG, "Generating FRACTINT.DOC");
putstring(7, 30, C_HELP_BODY, "Completed:");
movecursor(25,80); /* hide cursor */
}
sprintf(temp, "%d%%", (int)( (100.0 / num_pages) * pnum ) );
putstring(7, 41, C_HELP_LINK, temp);
while ( keypressed() )
{
key = getakey();
if ( key == ESC )
return (0); /* user abort */
}
return (1); /* AOK -- continue */
}
int makedoc_msg_func(int pnum, int num_pages)
{
if (pnum >= 0)
{
printf("\rcompleted %d%%", (int)( (100.0 / num_pages) * pnum ) );
return (1);
}
if ( pnum == -2 )
printf("\n*** aborted");
printf("\n");
return (0);
}
void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg )
{
static char far err_no_temp[] = "Unable to create temporary file.\n";
static char far err_no_out[] = "Unable to create output file.\n";
static char far err_badwrite[] = "Error writing temporary file.\n";
static char far err_badread[] = "Error reading temporary file.\nSystem may be corrupt!\nSave your image and re-start FRACTINT!\n";
PRINT_DOC_INFO info;
int success;
int temp_file = -1;
char far *msg = NULL;
ENTER_OVLY(OVLY_HELP);
info.buffer = MK_FP(extraseg, 0);
/* help_seek((long)sizeof(int)+sizeof(long)); Strange -- should be 8 -- CWM */
help_seek(8L); /* indeed it should - Bert */
read(help_file, (char *)&info.num_contents, sizeof(int));
read(help_file, (char *)&info.num_page, sizeof(int));
info.cnum = info.tnum = -1;
info.content_pos = sizeof(long)+4*sizeof(int) + num_topic*sizeof(long) + num_label*2*sizeof(int);
info.msg_func = msg_func;
if ( msg_func != NULL )
msg_func(0, info.num_page); /* initialize */
if ( save_extraseg )
{
if ( (temp_file=open(TEMP_FILE_NAME, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IREAD|S_IWRITE)) == -1 )
{
msg = err_no_temp;
goto ErrorAbort;
}
if ( farwrite(temp_file, info.buffer, PRINT_BUFFER_SIZE) != PRINT_BUFFER_SIZE )
{
msg = err_badwrite;
goto ErrorAbort;
}
}
if ( (info.file = fopen(outfname, "wt")) == NULL )
{
msg = err_no_out;
goto ErrorAbort;
}
info.margin = PAGE_INDENT;
info.start_of_line = 1;
info.spaces = 0;
success = process_document((PD_FUNC)print_doc_get_info,
(PD_FUNC)print_doc_output, &info);
fclose(info.file);
if ( save_extraseg )
{
if ( lseek(temp_file, 0L, SEEK_SET) != 0L )
{
msg = err_badread;
goto ErrorAbort;
}
if ( farread(temp_file, info.buffer, PRINT_BUFFER_SIZE) != PRINT_BUFFER_SIZE )
{
msg = err_badread;
goto ErrorAbort;
}
}
ErrorAbort:
if (temp_file != -1)
{
close(temp_file);
remove(TEMP_FILE_NAME);
temp_file = -1;
}
if ( msg != NULL )
{
helptitle();
stopmsg(1, msg);
}
else if ( msg_func != NULL )
msg_func((success) ? -1 : -2, info.num_page );
EXIT_OVLY;
}
int init_help(void)
{
struct help_sig_info hs;
char path[81];
ENTER_OVLY(OVLY_HELP);
help_file = -1;
#ifndef XFRACT
if (help_file == -1) /* now look for help files in FRACTINT.EXE */
{
static char far err_no_open[] = "Help system was unable to open FRACTINT.EXE!\n";
static char far err_no_exe[] = "Help system couldn't find FRACTINT.EXE!\n";
static char far err_wrong_ver[] = "Wrong help version in FRACTINT.EXE!\n";
/*
static char far err_not_in_exe[] = "Help not found in FRACTINT.EXE!\n";
*/
if ( find_file("FRACTINT.EXE", path) )
{
if ( (help_file = open(path, O_RDONLY|O_BINARY)) != -1 )
{
long help_offset;
for (help_offset = -((long)sizeof(hs)); help_offset >= -128L; help_offset--)
{
lseek(help_file, help_offset, SEEK_END);
read(help_file, (char *)&hs, sizeof(hs));
if (hs.sig == HELP_SIG) break;
}
if ( hs.sig != HELP_SIG )
{
close(help_file);
help_file = -1;
/* (leave out the error message)
stopmsg(1, err_not_in_exe);
*/
}
else
{
if ( hs.version != HELP_VERSION )
{
close(help_file);
help_file = -1;
stopmsg(1, err_wrong_ver);
}
else
base_off = hs.base;
}
}
else
stopmsg(1, err_no_open);
}
else
stopmsg(1, err_no_exe);
}
#endif
if (help_file == -1) /* look for FRACTINT.HLP */
{
if ( find_file("fractint.hlp", path) )
{
if ( (help_file = open(path, O_RDONLY|O_BINARY)) != -1 )
{
read(help_file, (char *)&hs, sizeof(long)+sizeof(int));
if ( hs.sig != HELP_SIG )
{
static char far msg[] = {"Invalid help signature in FRACTINT.HLP!\n"};
close(help_file);
stopmsg(1, msg);
}
else if ( hs.version != HELP_VERSION )
{
static char far msg[] = {"Wrong help version in FRACTINT.HLP!\n"};
close(help_file);
stopmsg(1, msg);
}
else
base_off = sizeof(long)+sizeof(int);
}
}
}
if (help_file == -1) /* Can't find the help files anywhere! */
{
static char far msg[] =
{"Help Files aren't in FRACTINT.EXE, and couldn't find FRACTINT.HLP!\n"};
stopmsg(1, msg);
}
help_seek(0L);
read(help_file, (char *)&max_pages, sizeof(int));
read(help_file, (char *)&max_links, sizeof(int));
read(help_file, (char *)&num_topic, sizeof(int));
read(help_file, (char *)&num_label, sizeof(int));
help_seek((long)6*sizeof(int)); /* skip num_contents and num_doc_pages */
assert(max_pages > 0);
assert(max_links >= 0);
assert(num_topic > 0);
assert(num_label > 0);
/* allocate one big chunk for all three arrays */
topic_offset = (long far *)farmemalloc(sizeof(long)*num_topic + 2L*sizeof(int)*num_label + sizeof(HIST)*MAX_HIST);
if (topic_offset == NULL)
{
static char far err_no_mem[] = "Not enough memory for help system!\n";
close(help_file);
help_file = -1;
stopmsg(1, err_no_mem);
EXIT_OVLY; /* JIC stopmsg continues for some reason? */
return (-2);
}
/* split off the other arrays */
label = (LABEL far *)(&topic_offset[num_topic]);
hist = (HIST far *)(&label[num_label]);
/* read in the tables... */
farread(help_file, topic_offset, num_topic*sizeof(long));
farread(help_file, label, num_label*2*sizeof(int));
/* finished! */
EXIT_OVLY;
return (0); /* success */
}
void end_help(void)
{
ENTER_OVLY(OVLY_HELP);
if (help_file != -1)
{
close(help_file);
farmemfree((BYTE far *)topic_offset);
help_file = -1;
}
EXIT_OVLY;
}